package com.briup.server.web.interceptor;

import com.briup.common.exception.ServiceException;
import com.briup.common.response.ResultCode;
import com.briup.common.utils.JwtUtil;
import com.briup.server.domain.vo.UserDetailVO;
import com.briup.server.security.Permission;
import com.briup.server.security.SecurityContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Arrays;
import java.util.List;

/**
 * 用户认证拦截器
 */
@Component
@RequiredArgsConstructor
public class AuthInterceptor implements HandlerInterceptor {

    @Value("${auth.token.header-name}")
    private String tokenHeaderName;
    private final RedisTemplate<String, Object> redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 预检请求直接通过
        if ("OPTIONS".equals(request.getMethod())) {
            return true;
        }

        // 不是预检请求，检查是否包含token
        String token = request.getHeader(tokenHeaderName);
        Long userId = JwtUtil.getInfo(token, "userId", Long.class);
        UserDetailVO userDetailVO = (UserDetailVO) redisTemplate.opsForValue()
                .get("userdetail:" + userId);
        // 设置当前用户到应用上下文
        SecurityContext.setCurrentUser(userDetailVO);

        // 检查用户是否具备访问本接口的权限
        if (!checkPermission(handler)) {
            throw new ServiceException(ResultCode.NO_PERMISSION);
        }

        return true;
    }

    private boolean checkPermission(Object handler) {
        // 如果是HandlerMethod类型，检查用户是否具备访问本接口的权限
        if (handler instanceof HandlerMethod handlerMethod) {
            // 获取标注在接口上的Permission注解
            Permission permission = handlerMethod.getMethodAnnotation(Permission.class);
            if (permission == null) {
                // 如果接口上没有标注Permission注解，表示所有用户都可以访问，直接放行
                return true;
            }
            // 如果标注了注解，那么检查用户是否具备权限
            String[] requiredPermissions = permission.value();
            List<String> permissions = Arrays.stream(requiredPermissions)
                    .map(String::toLowerCase).toList();
            // 获取当前用户的角色名列表
            List<String> roleNames = SecurityContext.roleNames();
            // 如果用户具备任意一个角色，那么就放行
            if (roleNames.stream().anyMatch(permissions::contains)) {
                return true;
            }
            // 如果用户不具备权限，返回false
            return false;
        }
        // 如果不是HandlerMethod类型，直接放行
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        SecurityContext.clear();
    }
}
